#ifndef _CHARGE_H_
#define _CHARGE_H_

#include "charge_os.h"
#include "charge_protocol.h"

#ifdef __cplusplus
extern "C"{
#endif

#define CARD_ID_LEN                     32
#define APP_ACCOUNT_LEN                 11
#define APP_PASSWORD_LEN                30
#define PERIOD_LEN                      48 
#define PRICE_TPYE_LEN                  4

#define TIME_5_MIN                      300
#define TIME_15_SEC                     15
#define TIME_60_SEC                     60

#define TIME_20_SEC						20

#define CMD_RESPONSE_TIMEOUT            5               //发送需要平台回复的数据后，5秒内未收到回复则重发
#define CMD_RESEND_TIMES                3               //重发3次

// 朔云使用固定参数，青莲云使用配置参数  2021-08-23 zhouhao
#define USING_FIXED_PARA                1
/*
    充电状态码
*/
#define CHARGE_STOP_FULL                0x1000      //已经充满
#define CHARGE_STOP_APP                 0x1001      //APP 远程停止
#define CHARGE_STOP_BALANCE             0x1002      //余额不足
#define CHARGE_STOP_SCREEN              0x1003      //结束充电，触控屏手动停止
#define CHARGE_STOP_PLATFROM            0x1004      //后台停止充电
#define CHARGE_STOP_TIME                0x1005      //充电时间满足设定条件
#define CHARGE_STOP_ELEC                0x1006      //充电电量满足设定条件
#define CHARGE_STOP_MONEY               0x1007      //充电金额满足设定条件
#define CHARGE_STOP_CARD                0x1008      //结束充电，手动刷卡停止充电
#define CHARGE_STOP_NO_EFFEC_CURR       0x1009      //无有效电流停止
#define CHARGE_STOP_BMS_ERR             0x100A      //BMS异常终止充电
#define CHARGE_STOP_BMS_CONDITION       0x100B      //BMS达到终止条件停止
#define CHARGE_STOP_PILE_CONDITION      0x100C      //充电桩达到终止条件停止
#define CHARGE_STOP_GUN_CONN_ERR        0x100D      //枪未正确连接
#define CHARGE_STOP_PULL_GUN            0x100E      //结束充电，充电过程中拔枪
#define CHARGE_STOP_APP_ACCOUNT         0x100F      //结束充电，APP账号停止充电
#define CHARGE_STATE_ERR                0xFFFF      //充电枪正在充电时收到开始充电指令，或未在充电时收到停止充电指令

/****************************************************
    账户余额
*****************************************************/
typedef enum
{
    TYPE_FULL_POWER = 0,                //满充
    TYPE_MONEY,                         //金额
    TYPE_TIME,                          //时间
    TYPE_ELECTRICITY,                   //电度
}balance_type;

typedef struct account
{
    uint32_t balance;                   //账户余额(单位0.01元)
    balance_type type;                  
    uint32_t value;                     //满充为0；按金额充，单位:0.01元；按时间充，单位:分钟；按电度充，单位:0.1度
}account_t;

typedef struct
{
    uint16_t    price_elec[PRICE_TPYE_LEN];                 //依次保存四种计费时段，尖、高、平、谷的对应价格，单位:分
    uint16_t    price_service[PRICE_TPYE_LEN];              //依次保存四种计费时段，尖、高、平、谷的对应价格，单位:分
    uint8_t     period[PERIOD_LEN];                         //每半小时一个时段，一天共48个时段，每个时段对应四种价格的某一种
} price_t;

/****************************************************
    计费信息
*****************************************************/
typedef struct
{
    uint32_t                start_time;                     //开始充电时间
    uint32_t                end_time;                       //结束时间
    uint16_t                total_time;                     //累计充电时间
    uint32_t                start_kwh;                      //开始充电时候的电量值(电表中读出, IEEE 格式传输 浮点数，单位度)
    uint32_t                total_kwh;                      //充电总度数
    uint32_t                total_fee_elec;                 //充电总电费
    uint32_t                total_fee_service;              //充电总服务费
    uint16_t                stop_code;

    //详细信息
    uint32_t                period_power[PERIOD_LEN];       //时间电量

    price_t                 price_info;
} fee_t;

#define START_MODE_APP              0x01
#define START_MODE_CARD             0x02
#define START_MODE_VIN              0x03
#define START_MODE_APP_ACCOUNT      0x04
#define START_MODE_PLATFORM         0x05

typedef enum
{
    CARD_STATE_UNLOCK = 0,
    CARD_STATE_LOCK,
} CARD_STATE_t;

typedef enum
{
    VIN_STATE_UNLOCK = 0,
    VIN_STATE_LOCK,
} VIN_STATE_t;

typedef enum
{
    APP_STATE_UNLOCK = 0,
    APP_STATE_LOCK,
} APP_STATE_t;

typedef enum EVENT_TYPE
{
    EVENT_TYPE_ALARM                        = 0,
    EVENT_TYPE_CONNECT                      = 1,
    EVENT_TYPE_CHARGE_IDLE                  = 2,
    EVENT_TYPE_CHARGE_READY                 = 3,
    EVENT_TYPE_CHARGE_BY_CARD               = 4,
    EVENT_TYPE_CHARGE_START                 = 5,
    EVENT_TYPE_PULL_GUN                     = 6,
    EVENT_TYPE_EMERG_BTN                    = 7,
    EVENT_TYPE_CHARGE_STOP                  = 8,
    EVENT_TYPE_REBOOT                       = 9,
    EVENT_TYPE_LOCK_SWITCH                  = 10,
    EVENT_TYPE_GET_INFO                     = 11,
    EVENT_TYPE_FAULT                        = 12,
    EVENT_TYPE_FAULT_RECOVER                = 13,
    EVENT_TYPE_SEND_VERSION                 = 14,
    EVENT_TYPE_OTA_RSP                      = 15,
    EVENT_TYPE_OTA_DOWNLOADING              = 16,
    EVENT_TYPE_OTA_DOWNLOAD_DONE            = 17,
    EVENT_TYPE_CHARGE_BY_VIN                = 18,
    EVENT_TYPE_CHARGE_BY_APP_ACCOUNT        = 19,
    EVENT_TYPE_CHARGE_STOP_BY_APP_ACCOUNT   = 20,
    EVENT_TYPE_POWER_ALLOC                  = 21,
    EVENT_TYPE_QR_CODE                      = 22,
    EVENT_TYPE_SET_PARAMS                   = 23,
    EVENT_TYPE_GUN_RELEASE                  = 24,
    EVENT_TYPE_VEHICLE_FAULT                = 25,
    EVENT_TYPE_VEHICLE_AUTO_STOP            = 26,
	EVENT_TYPE_GUN_FAULT_UPLOAD				= 27
} EVENT_TYPE;

#define EVENT_SET_BIT       0x80
#define EVENT_CLR_BIT       0x7F
#define EVENT_BUF_LEN       (( 3 * CHARGE_GUN_CNT + 8) * sizeof(event_item_t))//14

typedef enum
{
    EV_PARAM_TYPE_CMD        = 1,
    EV_PARAM_TYPE_GUN        = 2
} EV_PARAM_TYPE;

typedef struct charge_event_item //size:16 Bytes <todo> need change to 12
{
    uint8_t                 type;       //first bit is SET(1) or NOT SET(0),the other 7 bits are "EVENT_TYPE"
    union
    {
        struct 
        {
            uint8_t         cmd;        //cmd that need to be sent cyclically
            uint16_t        time_out;   //timer interval
            void            *param;
            uint32_t        time_last;  //last time of sending cmd
        } alarm;
        struct
        {
            uint8_t         gun_id;
            uint16_t        seq;
            void            *param;
        } common;
    } ev;
} event_item_t;

#define EVENT_MUTEX_TIME        100

typedef struct charge_event //size:12 Bytes
{
    event_item_t     *start;
    event_item_t     *curr;
    event_item_t     *end;
    os_mutex_t       ev_mutex;
} charge_event_t;

#if SUPPORT_OFFLINE_CARD
#define OFFLINE_BILLS_CNT               (CHARGE_GUN_CNT * BILLS_OF_A_GUN)
#else
#define OFFLINE_BILLS_CNT               CHARGE_GUN_CNT
#endif

#define SIZE_OF_ONE_BILL                375
#define GUN_ID_INDEX                    32
typedef uint8_t bill_array_t[SIZE_OF_ONE_BILL];

typedef enum{    
    BILL_NOT_SET                        = 0,//未设置
    BILL_ROM                            = 1,//从持久化存储器中读取的账单
    BILL_RAM                            = 2,//从内存中读取的账单
}bill_status_t;

typedef struct{
    bill_status_t                       status;
    bill_array_t                        bill;
}offline_bill_t;

#define LOCAL_CONFIG_MAGIC              0xA5A55A5A
#define MAGIC_ELEC                      (LOCAL_CONFIG_MAGIC&0xFFFF0000)
#define MAGIC_SERVICE                   (LOCAL_CONFIG_MAGIC&0x0000FFFF)

typedef struct
{
    uint16_t                period_chargeing;                   //充电枪充电时上报枪状态时间间隔，默认15秒
    uint16_t                period_heartbeat;                   //心跳上报周期，默认60秒
    uint16_t                heartbeat_timeout_cnt;              //心跳包检测超时次数，默认3次
    uint16_t                period_environment;                 //上报环境数据时间间隔
    uint16_t                period_await;                       //待机时上报枪状态时间间隔
    uint16_t                period_chargeing_bms;               //充电时上报BMS状态时间间隔
    uint16_t                period_time_sync;                   //网络时间同步指令时间间隔
    uint16_t                period_lock;                        //地锁状态同步时间间隔
    uint16_t                period_calc_bill;                   //计算账单费用间隔
    uint16_t                cmd_response_timeout;               //发送需要平台回复的数据后，几秒内未收到回复则重发，默认5秒
    uint16_t                cmd_resend_times;                   //重发次数，默认3次
    uint8_t                 log_lvl;                            //TCU日志打印level,1消息,2DEBUG,3告警,4错误
    uint8_t                 log_up_strategy;                    //TCU日志上传策略,1按时间间隔,2按文件轮转,3 Null不主动上传
    uint16_t                log_period;                         //TCU日志上传时间间隔,单位分钟
} pile_param_t;

typedef struct
{
    uint32_t                            magic;//04
    price_t                             price;                          //计费策略
    pile_param_t                        param;                          //充电桩参数设置
    uint8_t                             reserved[128];                  //预留空间,为了兼容后期可能本地存储数据
    offline_bill_t                      off_bill[OFFLINE_BILLS_CNT];
} local_config_t;

typedef struct
{
    uint8_t                 gun_id;                             //枪号
    GUN_STATE_t             gun_state;                          //枪状态
    uint8_t                 start_mode;                         //启动方式 01:app远程启动；02:刷卡启动;03:VIN码启动；04:APP账号启动
    uint8_t                 card_id[CARD_ID_LEN + 1];           //卡号，刷卡充电时有效
    uint8_t                 app_account[APP_ACCOUNT_LEN + 1];   //app账号
    uint8_t                 app_password[APP_PASSWORD_LEN + 1]; //app密码
    CARD_STATE_t            card_state;                         //刷卡状态
    VIN_STATE_t             vin_state;                          //vin启动状态
    APP_STATE_t             app_state;                          //app账号启动状态
    uint16_t                gun_fault_code;                     //开始/停止充电、功率分配的错误码
    user_gun_t              *u_gun;                             //用户提供的枪数据
    user_bms_t              *bms;                               //用户提供的BMS数据
    user_lock_t             *lock;                              //用户提供的地锁数据
    account_t               account;                            //账户余额
    fee_t                   fee;                                //本地计费信息
    uint8_t                 lock_switch;                        //地锁开关
    uint8_t                 lock_fault_code;                    //控制地锁错误码
    uint32_t                max_out_power;                      //最大输出功率
    uint8_t                 cmd_response_status;                //指令响应状态
} gun_t;

typedef struct charger
{
    user_pile_t             *pile;                      //桩结构体
    gun_t                   gun[CHARGE_GUN_CNT];        //枪结构体  
    uint8_t                 ev_buf[EVENT_BUF_LEN];      //事件缓冲长度
    charge_event_t          event;                      //事件结构体
    net_client_t            net_client;                 //网络客户端结构体
    local_config_t          local_cfg;                  //本地配置信息
    uint8_t                 pile_cmd;                   //控制充电桩的命令
    uint16_t                error_code;                 //桩状态码
    ota_info_t              ota_info;                   //ota数据包信息
} charger_t;

/*数据存入队列*/
int32_t net_queue_en(net_queue_t *q, uint16_t data_len, uint8_t cmd, uint16_t seq);

/*clean the data which has been sent.*/
void net_queue_clean_sent(net_queue_t *q);

int32_t event_add_common(charge_event_t *e, uint8_t type, uint8_t gun_id, void *param, uint16_t seq);

void event_del_all_except_bill(charge_event_t *e);

//获取当前时段
uint8_t time_get_period(void);

int8_t bill_update(uint8_t *buf, uint32_t len);
int8_t bill_compare(net_client_t *client, uint8_t *buf, uint32_t len);
int32_t bill_delete(int8_t bill_index);
int32_t bill_save(int8_t bill_index);

int get_gun_fee(uint8_t gun_idx, fee_t * p_fee);

int get_gun_account(uint8_t gun_idx, account_t * p_account);

#ifdef __cplusplus
}
#endif

#endif
